﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace MyUtils.Core
{
    #region websocket工具
    /// <summary>
    /// Websocket工具
    /// </summary>
    public static class WebSocketUtil
    {
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="ws"></param>
        /// <param name="data"></param>
        public static void Send(this WebSocket ws, string data)
        {
            if (ws != null && ws.State == WebSocketState.Open)
            {
                var recvBytes = Encoding.UTF8.GetBytes(data);
                var sendBuffer = new ArraySegment<byte>(recvBytes);
                ws.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
        }

        /// <summary>
        /// 群发信息
        /// </summary>
        /// <param name="wss"></param>
        /// <param name="data"></param>
        /// <param name="ignoreWs"></param>
        public static void Send(this List<WebSocket> wss,string data, WebSocket ignoreWs = null)
        {
            if (wss != null && wss.Count > 0)
            {
                var recvBytes = Encoding.UTF8.GetBytes(data);
                var sendBuffer = new ArraySegment<byte>(recvBytes);
                foreach (var ws in wss)
                {
                    if (ws != null && ws.State == WebSocketState.Open)
                    {
                        if (ws == ignoreWs)
                            continue;
                        ws.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
            }
        }


        /// <summary>
        /// 关闭websocket连接
        /// </summary>
        /// <param name="ws"></param>
        public static void Close(this WebSocket ws)
        {
            try
            {
                if (ws != null && ws.State == WebSocketState.Open)
                    ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
            }
            catch (Exception)
            {
            }
        }


        /// <summary>
        /// websocket处理器
        /// </summary>
        /// <param name="ws">websocket句柄</param>
        /// <param name="ctx">调用者设置的上下文对象</param>
        /// <param name="initAction">初始化时执行内容</param>
        /// <param name="onMessage">接受到信息后执行内容</param>
        /// <param name="errorAction">异常后执行内容</param>
        /// <param name="finilyAction">最后执行内容</param>
        /// <returns></returns>
        public static async Task Handler<T>(this WebSocket ws, T ctx, Action<WebSocket, T> initAction,Action<WebSocket,string, T> onMessage, Action<WebSocket, Exception, T> errorAction, Action<WebSocket, T> finilyAction)
        {
            bool init = false;
            // 用于存放所有传输的字节
            var bs = new List<byte>();
            // 用于存放每次管道内传输的字节
            var buffer = new ArraySegment<byte>(new byte[256]);
            try
            {
                while (true)
                {
                    var receivedResult = await ws.ReceiveAsync(buffer, CancellationToken.None);
                    if (receivedResult.MessageType == WebSocketMessageType.Close)
                        break;

                    if (init == false && initAction != null)
                    {
                        initAction(ws, ctx);
                        init = true;
                    }

                    // websocket通道内的数据
                    bs.AddRange(buffer.Take(receivedResult.Count));
                    // 清空buffer
                    buffer.Array.AsSpan().Fill(0);

                    // 接受完所有数据标记
                    if (receivedResult.EndOfMessage)
                    {
                        var message = Encoding.UTF8.GetString(bs.ToArray(), 0, bs.Count);
                        // 消息完成后需要清空bs
                        bs.Clear();
                        if (onMessage != null)
                            onMessage(ws, message, ctx);
                    }
                }
            }
            catch (Exception ex)
            {
                if (errorAction != null)
                    errorAction(ws, ex, ctx);
            }
            finally
            {
                if (finilyAction != null)
                    finilyAction(ws, ctx);
            }
        }
    
    }
    #endregion

    #region http请求工具
    public class HttpRequest
    {

    }
    #endregion

    #region webApi响应类
    /// <summary>
    /// api响应类
    /// </summary>
    public class ApiResponse
    {
        public int Code { get; set; }
        public string Message { get; set; }
        public object Data { get; set; }

        public static ApiResponse Success(object data)
        {
            var ret = new ApiResponse();
            ret.Code = 0;
            ret.Data = data;
            return ret;
        }
        public static ApiResponse Success()
        {
            var ret = new ApiResponse();
            ret.Code = 0;
            return ret;
        }

        public static ApiResponse Error(Exception ex)
        {
            var ret = new ApiResponse();
            ret.Code = -1;
            ret.Message = ex.Message;
            return ret;
        }


        public static ApiResponse Error(string message)
        {
            var ret = new ApiResponse();
            ret.Code = -1;
            ret.Message = message;
            return ret;
        }

    }
    #endregion

    #region ftp工具
    /// <summary>
    /// FTP工具类
    /// </summary>
    public class FtpUtil
    {
        #region 文件夹是否存在
        /// <summary>
        /// 文件夹是否存在
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="folderName">文件夹名称</param>
        public static bool FolderExists(string ftpPath, string ftpUserId, string ftpPassword, string folderName)
        {
            try
            {
                FtpWebRequest request = null;

                request = (FtpWebRequest)WebRequest.Create(new Uri(ftpPath));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "LIST";
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                string str = Encoding.UTF8.GetString(stream.ToArray());
                foreach (string line in str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (line.ToUpper().Contains("DIR") || line.ToUpper().Contains("DR"))
                    {
                        int pos = line.LastIndexOf(" ");
                        string folder = line.Substring(pos).Trim();
                        if (folder == folderName)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return false;
        }
        #endregion

        #region 创建文件夹
        /// <summary>
        /// 创建文件夹
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="folderName">文件夹名称</param>
        public static void CreateFolder(string ftpPath, string ftpUserId, string ftpPassword, string folderName)
        {
            try
            {
                FtpWebRequest request = null;

                request = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine(ftpPath, folderName).Replace("\\", "/")));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "MKD";
                ((FtpWebResponse)request.GetResponse()).Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 文件是否存在
        /// <summary>
        /// 文件是否存在
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public static bool FileExists(string ftpPath, string ftpUserId, string ftpPassword, string relativeFilePath)
        {
            try
            {
                FtpWebRequest request = null;

                string folderName = Path.GetDirectoryName(relativeFilePath);
                string fileName = Path.GetFileName(relativeFilePath);
                request = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine(ftpPath, folderName).Replace("\\", "/")));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "LIST";
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                string str = Encoding.UTF8.GetString(stream.ToArray());
                foreach (string line in str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (!line.ToUpper().Contains("DIR") && !line.ToUpper().Contains("DR"))
                    {
                        int pos = line.LastIndexOf(" ");
                        string strFileName = line.Substring(pos).Trim();
                        if (strFileName == fileName)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return false;
        }
        #endregion

        #region 下载文件
        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public static MemoryStream DownloadFile(string ftpPath, string ftpUserId, string ftpPassword, string relativeFilePath)
        {
            try
            {
                FtpWebRequest request = null;

                request = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine(ftpPath, relativeFilePath).Replace("\\", "/")));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "RETR";
                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = responseStream.Read(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = responseStream.Read(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                return stream;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 异步下载文件
        /// <summary>
        /// 异步下载文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public static async Task<MemoryStream> DownloadFileAsync(string ftpPath, string ftpUserId, string ftpPassword, string relativeFilePath)
        {
            try
            {
                FtpWebRequest request = null;

                request = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine(ftpPath, relativeFilePath).Replace("\\", "/")));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "RETR";
                FtpWebResponse response = (FtpWebResponse)(await request.GetResponseAsync());
                Stream responseStream = response.GetResponseStream();
                MemoryStream stream = new MemoryStream();
                byte[] bArr = new byte[1024 * 1024];
                int size = await responseStream.ReadAsync(bArr, 0, (int)bArr.Length);
                while (size > 0)
                {
                    stream.Write(bArr, 0, size);
                    size = await responseStream.ReadAsync(bArr, 0, (int)bArr.Length);
                }
                stream.Seek(0, SeekOrigin.Begin);
                responseStream.Close();

                return stream;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 上传文件
        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        /// <param name="bArr">文件内容</param>
        public static void UploadFile(string ftpPath, string ftpUserId, string ftpPassword, string relativeFilePath, byte[] bArr)
        {
            try
            {
                FtpWebRequest request = null;

                request = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine(ftpPath, relativeFilePath).Replace("\\", "/")));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "STOR";
                Stream postStream = request.GetRequestStream();
                int pageSize = 1024 * 1024;
                int index = 0;
                while (index < bArr.Length)
                {
                    if (bArr.Length - index > pageSize)
                    {
                        postStream.Write(bArr, index, pageSize);
                        index += pageSize;
                    }
                    else
                    {
                        postStream.Write(bArr, index, bArr.Length - index);
                        index = index + (bArr.Length - index);
                    }
                }
                postStream.Close();

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Stream responseStream = response.GetResponseStream();
                StreamReader sr = new StreamReader(responseStream, Encoding.UTF8);
                string result = sr.ReadToEnd();
                responseStream.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

        #region 删除文件
        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="ftpPath">ftp路径</param>
        /// <param name="ftpUserId">用户名</param>
        /// <param name="ftpPassword">密码</param>
        /// <param name="relativeFilePath">文件相对路径</param>
        public static void DeleteFile(string ftpPath, string ftpUserId, string ftpPassword, string relativeFilePath)
        {
            try
            {
                FtpWebRequest request = null;

                request = (FtpWebRequest)WebRequest.Create(new Uri(Path.Combine(ftpPath, relativeFilePath).Replace("\\", "/")));
                request.Credentials = new NetworkCredential(ftpUserId, ftpPassword);
                request.Method = "DELE";
                ((FtpWebResponse)request.GetResponse()).Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        #endregion

    }
    #endregion
}
